package com.liu.communitysystemend.security.filter;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.liu.communitysystemend.module.memu.domain.Menu;
import com.liu.communitysystemend.module.memu.service.MenuService;
import com.liu.communitysystemend.module.memu.service.impl.MenuServiceImpl;
import com.liu.communitysystemend.security.component.JwtTokenUtils;
import com.liu.communitysystemend.security.domain.JwtUser;
import com.liu.communitysystemend.security.domain.LoginUser;
import com.liu.communitysystemend.utils.JsonResult;
import com.liu.communitysystemend.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

/**
 * @author liu
 * @create 2023-02-17 20:35
 */
@Slf4j
public class JWTAuthenticationFilter  extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

     RedisUtil redisUtil;
     JwtTokenUtils jwtTokenUtils;
     private MenuServiceImpl menuService;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager){
        this.authenticationManager= authenticationManager;
        super.setFilterProcessesUrl("/auth/login");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        ServletContext servletContext = request.getServletContext();
        WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        assert webApplicationContext!=null;
        try {
            LoginUser loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUser.class);
            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginUser.getUsername(),loginUser.getPassword()));
        }catch (Exception e){
            try {
                log.error(e.toString() + " ：" + e.getMessage());
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=utf-8");
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                String reason = JsonResult.failed(202, "用户名或密码错误");
                response.getWriter().write(new ObjectMapper().writeValueAsString(reason));
                response.getWriter().flush();
            } catch (IOException ioException) {
                log.error(e.toString() + " : " + e.getMessage());
            }
        }

        return null;
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

        JwtUser jwtUser = (JwtUser)authResult.getPrincipal();
        log.info("jwtUser" + jwtUser.toString());
        String role="";
        Collection<? extends GrantedAuthority> authorities = jwtUser.getAuthorities();
        for (GrantedAuthority authority : authorities){
            role=authority.getAuthority();
        }
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");
        //获取容器
        ServletContext context = request.getServletContext();
        ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(context);
        assert ac != null;
        jwtTokenUtils = ac.getBean(JwtTokenUtils.class);
        redisUtil= ac.getBean(RedisUtil.class);
        menuService = ac.getBean(MenuServiceImpl.class);
        String token = jwtTokenUtils.createToken(jwtUser.getId(), role);
        HashMap<String, Object> map = new HashMap<>();
        map.put("id",jwtUser.getId());
        map.put("role",role);
        map.put("username",jwtUser.getUsername());
        List<Menu> menuList = menuService.getMenuList(role);
        redisUtil.hset(jwtTokenUtils.TOKEN_PREFIX+" "+token,map,720000000L);
        response.setHeader("token", jwtTokenUtils.TOKEN_PREFIX + " " + token);
        map.remove("id");
        map.put("token", jwtTokenUtils.TOKEN_PREFIX + " " + token);
        map.put("id", jwtTokenUtils.getUsername(token));
        map.put("role", jwtTokenUtils.getUserRole(token));
        map.put("menuList",menuList);
        response.getWriter().write(JsonResult.success(200, "登录成功", map));
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.getWriter().write(JsonResult.failed(102,failed.getMessage()));
    }
}
